package com.xuecheng.checkcode.service.impl;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.xuecheng.checkcode.model.CheckCodeParamsDto;
import com.xuecheng.checkcode.model.CheckCodeResultDto;
import com.xuecheng.checkcode.service.AbstractCheckCodeService;
import com.xuecheng.checkcode.service.CheckCodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;

/**
 * @author Mr.M
 * @version 1.0
 * @description 图片验证码生成器
 * @date 2022/9/29 16:16
 */
@Service("PicCheckCodeService")
public class PicCheckCodeServiceImpl extends AbstractCheckCodeService implements CheckCodeService {


    @Autowired
    private DefaultKaptcha kaptcha;

    @Resource(name="NumberLetterCheckCodeGenerator")
    @Override
    public void setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator) {
        this.checkCodeGenerator = checkCodeGenerator;
    }

    @Resource(name="UUIDKeyGenerator")
    @Override
    public void setKeyGenerator(KeyGenerator keyGenerator) {
        this.keyGenerator = keyGenerator;
    }


    @Resource(name="RedisCheckCodeStore")
    @Override
    public void setCheckCodeStore(CheckCodeStore checkCodeStore) {
        this.checkCodeStore = checkCodeStore;
    }


    @Override
    //生成验证码图片和key 提供给前端的认证页面进行输入验证码 前端也是有key的只不过是隐藏了
    //前端输入完以后就拿着输入的验证码和key提交到认证服务 认证服务就会调用验证码的verify接口进行校验
    //重写的模板里面的第二个generate方法 先走的模板 再走这里 然后又回到模板
    public CheckCodeResultDto generate(CheckCodeParamsDto checkCodeParamsDto) {
        //调用的抽象类里面的generate
        //checkCodeParamsDto生成验证码参数 4表示验证码的长度 checkcode表示key的前缀去看测试里面就知道了 300表示验证码的有效时间
        GenerateResult generate = generate(checkCodeParamsDto, 4, "checkcode:", 300);
        //通过UUID生成的
        String key = generate.getKey();
        //通过自定义的一个字符串生成的
        String code = generate.getCode();
        String pic = createPic(code);
        CheckCodeResultDto checkCodeResultDto = new CheckCodeResultDto();
        //pic和key要返回给前端的 用于页面的验证码图片展示
        //然后前端提交验证码的时候会把key也带上 然后根据key去redis里面对比code验证码匹不匹配 匹配的话就把数据删了释放空间
        checkCodeResultDto.setAliasing(pic);
        checkCodeResultDto.setKey(key);
        return checkCodeResultDto;

    }

    private String createPic(String code) {
        // 生成图片验证码
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        //Kaptcha 是一个 Java 库，用于生成随机验证码图片，通常用于网页或应用程序中的验证码验证功能。
        BufferedImage image = kaptcha.createImage(code);

        String imgBase64Encoder = null;
        try {
            ImageIO.write(image, "png", outputStream);
            // 对字节数组Base64编码
            byte[] imageBytes = outputStream.toByteArray();
            imgBase64Encoder = "data:image/png;base64," + Base64.getEncoder().encodeToString(imageBytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //Base64 编码的字符串本身并不是一张图片，它是一种将二进制数据编码为文本字符串的方法
        //要将 Base64 编码的字符串还原为图片，需要进行解码操作。在网页中，可以将这个 Base64 编码的字符串放置在 <img> 标签的 src 属性中，浏览器会自动将其解码并显示为图片。
        return imgBase64Encoder;
    }
}
